import json
from typing import Dict, List, Set


class Student:
    def __init__(self, student_id: str, name: str, age: int):
        self.student_id = student_id
        self.name = name
        self.age = age
        self.courses: Set[str] = set()

    def enroll_course(self, course_name: str):
        self.courses.add(course_name)

    def drop_course(self, course_name: str):
        if course_name in self.courses:
            self.courses.remove(course_name)

    def to_dict(self) -> Dict:
        return {
            'student_id': self.student_id,
            'name': self.name,
            'age': self.age,
            'courses': list(self.courses)
        }

    @classmethod
    def from_dict(cls, data: Dict):
        student = cls(data['student_id'], data['name'], data['age'])
        for course in data['courses']:
            student.enroll_course(course)
        return student

    def __str__(self):
        return f"ID: {self.student_id}, Name: {self.name}, Age: {self.age}, Courses: {', '.join(self.courses)}"


class Course:
    def __init__(self, name: str, credit: int):
        self.name = name
        self.credit = credit

    def to_dict(self) -> Dict:
        return {
            'name': self.name,
            'credit': self.credit
        }

    @classmethod
    def from_dict(cls, data: Dict):
        return cls(data['name'], data['credit'])

    def __str__(self):
        return f"Course: {self.name}, Credit: {self.credit}"


class StudentManagementSystem:
    def __init__(self):
        self.students: Dict[str, Student] = {}  # 用字典快速查找
        self.student_list: List[Student] = []  # 保持插入顺序
        self.courses: Dict[str, Course] = {}

    def add_student(self, student: Student):
        if student.student_id in self.students:
            raise ValueError("Student ID already exists")
        self.students[student.student_id] = student
        self.student_list.append(student)

    def remove_student(self, student_id: str):
        if student_id not in self.students:
            raise ValueError("Student not found")
        student = self.students.pop(student_id)
        self.student_list.remove(student)

    def add_course(self, course: Course):
        if course.name in self.courses:
            raise ValueError("Course already exists")
        self.courses[course.name] = course

    def enroll_student_to_course(self, student_id: str, course_name: str):
        if student_id not in self.students:
            raise ValueError("Student not found")
        if course_name not in self.courses:
            raise ValueError("Course not found")
        self.students[student_id].enroll_course(course_name)

    def save_to_file(self, filename: str):
        data = {
            'students': [student.to_dict() for student in self.student_list],
            'courses': [course.to_dict() for course in self.courses.values()]
        }
        with open(filename, 'w') as f:
            json.dump(data, f, indent=2)

    def load_from_file(self, filename: str):
        try:
            with open(filename, 'r') as f:
                data = json.load(f)

            self.students.clear()
            self.student_list.clear()
            self.courses.clear()

            for course_data in data['courses']:
                course = Course.from_dict(course_data)
                self.courses[course.name] = course

            for student_data in data['students']:
                student = Student.from_dict(student_data)
                self.add_student(student)
        except FileNotFoundError:
            print("File not found, starting with empty system")
        except json.JSONDecodeError:
            print("Invalid JSON file, starting with empty system")

    def display_all_students(self):
        for student in self.student_list:
            print(student)

    def display_all_courses(self):
        for course in self.courses.values():
            print(course)


# 示例用法
if __name__ == "__main__":
    system = StudentManagementSystem()

    # 从文件加载数据
    system.load_from_file("student_data.json")

    # 添加课程
    system.add_course(Course("Math", 4))
    system.add_course(Course("Physics", 3))
    system.add_course(Course("Computer Science", 5))

    # 添加学生
    system.add_student(Student("001", "Alice", 20))
    system.add_student(Student("002", "Bob", 21))
    system.add_student(Student("003", "Charlie", 19))

    # 选课
    system.enroll_student_to_course("001", "Math")
    system.enroll_student_to_course("001", "Computer Science")
    system.enroll_student_to_course("002", "Physics")
    system.enroll_student_to_course("003", "Math")
    system.enroll_student_to_course("003", "Physics")

    # 显示信息
    print("\nAll Students:")
    system.display_all_students()

    print("\nAll Courses:")
    system.display_all_courses()

    # 保存到文件
    system.save_to_file("student_data.json")

import json
from datetime import datetime, timedelta
from typing import Dict, List, Optional


class Book:
    def __init__(self, isbn: str, title: str, author: str, total_copies: int = 1):
        self.isbn = isbn
        self.title = title
        self.author = author
        self.total_copies = total_copies
        self.available_copies = total_copies

    def to_dict(self) -> Dict:
        return {
            'isbn': self.isbn,
            'title': self.title,
            'author': self.author,
            'total_copies': self.total_copies,
            'available_copies': self.available_copies
        }

    @classmethod
    def from_dict(cls, data: Dict):
        book = cls(data['isbn'], data['title'], data['author'], data['total_copies'])
        book.available_copies = data['available_copies']
        return book

    def __str__(self):
        return f"ISBN: {self.isbn}, Title: {self.title}, Author: {self.author}, Available: {self.available_copies}/{self.total_copies}"


class User:
    def __init__(self, user_id: str, name: str, max_borrow: int = 5):
        self.user_id = user_id
        self.name = name
        self.max_borrow = max_borrow
        self.borrowed_books: List[str] = []  # 存储借阅的图书ISBN

    def to_dict(self) -> Dict:
        return {
            'user_id': self.user_id,
            'name': self.name,
            'max_borrow': self.max_borrow,
            'borrowed_books': self.borrowed_books
        }

    @classmethod
    def from_dict(cls, data: Dict):
        user = cls(data['user_id'], data['name'], data['max_borrow'])
        user.borrowed_books = data['borrowed_books']
        return user

    def __str__(self):
        return f"ID: {self.user_id}, Name: {self.name}, Borrowed: {len(self.borrowed_books)}/{self.max_borrow}"


class BorrowRecord:
    def __init__(self, record_id: str, user_id: str, isbn: str, borrow_date: datetime, due_date: datetime,
                 returned: bool = False):
        self.record_id = record_id
        self.user_id = user_id
        self.isbn = isbn
        self.borrow_date = borrow_date
        self.due_date = due_date
        self.returned = returned

    def to_dict(self) -> Dict:
        return {
            'record_id': self.record_id,
            'user_id': self.user_id,
            'isbn': self.isbn,
            'borrow_date': self.borrow_date.strftime('%Y-%m-%d'),
            'due_date': self.due_date.strftime('%Y-%m-%d'),
            'returned': self.returned
        }

    @classmethod
    def from_dict(cls, data: Dict):
        borrow_date = datetime.strptime(data['borrow_date'], '%Y-%m-%d')
        due_date = datetime.strptime(data['due_date'], '%Y-%m-%d')
        return cls(
            data['record_id'],
            data['user_id'],
            data['isbn'],
            borrow_date,
            due_date,
            data['returned']
        )

    def __str__(self):
        status = "Returned" if self.returned else "Borrowed"
        return f"Record ID: {self.record_id}, User: {self.user_id}, Book: {self.isbn}, {status}, Borrowed: {self.borrow_date.strftime('%Y-%m-%d')}, Due: {self.due_date.strftime('%Y-%m-%d')}"


class LibrarySystem:
    def __init__(self):
        self.books: Dict[str, Book] = {}  # ISBN -> Book
        self.users: Dict[str, User] = {}  # User ID -> User
        self.records: Dict[str, BorrowRecord] = {}  # Record ID -> Record
        self.book_list: List[Book] = []  # 保持图书插入顺序
        self.user_list: List[User] = []  # 保持用户插入顺序

    def add_book(self, book: Book):
        if book.isbn in self.books:
            # 如果图书已存在，增加库存
            existing = self.books[book.isbn]
            existing.total_copies += book.total_copies
            existing.available_copies += book.total_copies
        else:
            self.books[book.isbn] = book
            self.book_list.append(book)

    def remove_book(self, isbn: str, copies: int = 1):
        if isbn not in self.books:
            raise ValueError("Book not found")

        book = self.books[isbn]
        if copies > book.total_copies:
            raise ValueError("Cannot remove more copies than exist")
        if (book.total_copies - book.available_copies) > (book.total_copies - copies):
            raise ValueError("Cannot remove copies that are currently borrowed")

        book.total_copies -= copies
        book.available_copies -= copies

        if book.total_copies == 0:
            del self.books[isbn]
            self.book_list.remove(book)

    def add_user(self, user: User):
        if user.user_id in self.users:
            raise ValueError("User ID already exists")
        self.users[user.user_id] = user
        self.user_list.append(user)

    def remove_user(self, user_id: str):
        if user_id not in self.users:
            raise ValueError("User not found")

        user = self.users[user_id]
        if user.borrowed_books:
            raise ValueError("User has borrowed books and cannot be removed")

        del self.users[user_id]
        self.user_list.remove(user)

    def borrow_book(self, user_id: str, isbn: str, borrow_days: int = 30) -> str:
        if user_id not in self.users:
            raise ValueError("User not found")
        if isbn not in self.books:
            raise ValueError("Book not found")

        user = self.users[user_id]
        book = self.books[isbn]

        if len(user.borrowed_books) >= user.max_borrow:
            raise ValueError("User has reached maximum borrowing limit")
        if book.available_copies <= 0:
            raise ValueError("No available copies of this book")

        # 生成唯一的借阅记录ID
        record_id = f"{user_id}-{isbn}-{datetime.now().strftime('%Y%m%d%H%M%S')}"

        # 更新图书可用数量
        book.available_copies -= 1

        # 更新用户借阅列表
        user.borrowed_books.append(isbn)

        # 创建借阅记录
        borrow_date = datetime.now()
        due_date = borrow_date + timedelta(days=borrow_days)
        record = BorrowRecord(record_id, user_id, isbn, borrow_date, due_date)
        self.records[record_id] = record

        return record_id

    def return_book(self, record_id: str):
        if record_id not in self.records:
            raise ValueError("Borrow record not found")

        record = self.records[record_id]
        if record.returned:
            raise ValueError("Book already returned")

        # 更新记录状态
        record.returned = True

        # 更新图书可用数量
        book = self.books[record.isbn]
        book.available_copies += 1

        # 更新用户借阅列表
        user = self.users[record.user_id]
        user.borrowed_books.remove(record.isbn)

    def search_books(self, title: Optional[str] = None, author: Optional[str] = None, isbn: Optional[str] = None) -> \
    List[Book]:
        results = []
        for book in self.book_list:
            match = True
            if title and title.lower() not in book.title.lower():
                match = False
            if author and author.lower() not in book.author.lower():
                match = False
            if isbn and isbn != book.isbn:
                match = False
            if match:
                results.append(book)
        return results

    def get_user_records(self, user_id: str) -> List[BorrowRecord]:
        if user_id not in self.users:
            raise ValueError("User not found")

        return [record for record in self.records.values() if record.user_id == user_id]

    def save_to_file(self, filename: str):
        data = {
            'books': [book.to_dict() for book in self.book_list],
            'users': [user.to_dict() for user in self.user_list],
            'records': [record.to_dict() for record in self.records.values()]
        }
        with open(filename, 'w') as f:
            json.dump(data, f, indent=2)

    def load_from_file(self, filename: str):
        try:
            with open(filename, 'r') as f:
                data = json.load(f)

            # 清空当前数据
            self.books.clear()
            self.users.clear()
            self.records.clear()
            self.book_list.clear()
            self.user_list.clear()

            # 加载图书
            for book_data in data.get('books', []):
                book = Book.from_dict(book_data)
                self.add_book(book)

            # 加载用户
            for user_data in data.get('users', []):
                user = User.from_dict(user_data)
                self.add_user(user)

            # 加载记录
            for record_data in data.get('records', []):
                record = BorrowRecord.from_dict(record_data)
                self.records[record.record_id] = record
        except FileNotFoundError:
            print("File not found, starting with empty library")
        except json.JSONDecodeError:
            print("Invalid JSON file, starting with empty library")

    def display_all_books(self):
        for book in self.book_list:
            print(book)

    def display_all_users(self):
        for user in self.user_list:
            print(user)

    def display_all_records(self):
        for record in self.records.values():
            print(record)


# 示例用法
if __name__ == "__main__":
    library = LibrarySystem()

    # 从文件加载数据
    library.load_from_file("library_data.json")

    # 添加图书
    library.add_book(Book("978-3-16-148410-0", "Python Programming", "John Smith", 3))
    library.add_book(Book("978-1-23-456789-7", "Data Structures", "Alice Johnson", 2))
    library.add_book(Book("978-0-12-345678-9", "Algorithms", "Robert Martin", 5))

    # 添加用户
    library.add_user(User("001", "Tom", 3))
    library.add_user(User("002", "Jerry", 5))

    # 借书操作
    try:
        record_id1 = library.borrow_book("001", "978-3-16-148410-0", 14)
        print(f"Book borrowed, record ID: {record_id1}")

        record_id2 = library.borrow_book("002", "978-1-23-456789-7")
        print(f"Book borrowed, record ID: {record_id2}")
    except ValueError as e:
        print(f"Error: {e}")

    # 显示信息
    print("\nAll Books:")
    library.display_all_books()

    print("\nAll Users:")
    library.display_all_users()

    print("\nAll Records:")
    library.display_all_records()

    # 还书操作
    try:
        library.return_book(record_id1)
        print("\nBook returned successfully")
    except ValueError as e:
        print(f"\nError: {e}")

    # 搜索图书
    print("\nSearch results for 'Python':")
    for book in library.search_books(title="Python"):
        print(book)

    # 保存到文件
    library.save_to_file("library_data.json")


